"""
SQL运行器：支持多语句输入和分阶段输出
提供文件/stdin输入，输出各阶段结果（Token → AST → 语义 → 执行计划）
"""

import sys
import os
import json
from typing import List, Dict, Any

# 确保可以从项目根目录导入包
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from sql_compiler.lexer import Lexer, LexerError
from sql_compiler.parser import Parser, ParserError
from sql_compiler.semantic import SemanticAnalyzer, SemanticError
from sql_compiler.planner import Planner
from sql_compiler.catalog import Catalog
from engine.catalog_manager import CatalogManager, TableInfo, ColumnInfo
from engine.storage_engine import StorageEngine
from engine.executor import Executor

class SQLRunner:
    """SQL运行器，支持完整的编译和执行流程"""
    
    def __init__(self, output_format: str = "text"):
        """
        初始化SQL运行器
        
        Args:
            output_format: 输出格式，支持 "text", "json"
        """
        self.output_format = output_format
        self.catalog_manager = CatalogManager()
        self.storage_engine = StorageEngine()
        self.executor = Executor(self.catalog_manager, self.storage_engine)
        self.semantic_analyzer = SemanticAnalyzer(Catalog())
        self.planner = Planner()
        
        # 结果存储
        self.results = []
    
    def run_sql(self, sql: str, show_stages: bool = True) -> Dict[str, Any]:
        """
        运行SQL语句，返回各阶段结果
        
        Args:
            sql: SQL语句
            show_stages: 是否显示各阶段结果
            
        Returns:
            包含各阶段结果的字典
        """
        result = {
            "sql": sql,
            "stages": {},
            "success": False,
            "error": None
        }
        
        try:
            # 1. 词法分析
            if show_stages:
                print("=== 词法分析 ===")
            
            lexer = Lexer(sql)
            tokens = lexer.tokenize()
            
            if show_stages:
                self._print_tokens(tokens)
            
            result["stages"]["tokens"] = [token.to_list() for token in tokens]
            
            # 2. 语法分析
            if show_stages:
                print("\n=== 语法分析 ===")
            
            parser = Parser(tokens)
            ast_nodes = parser.parse()
            
            if show_stages:
                self._print_ast(ast_nodes)
            
            result["stages"]["ast"] = self._ast_to_dict(ast_nodes)
            
            # 3. 语义分析
            if show_stages:
                print("\n=== 语义分析 ===")
            
            try:
                self.semantic_analyzer.analyze(ast_nodes)
                if show_stages:
                    print("语义分析通过")
                result["stages"]["semantic"] = {"status": "passed"}
            except SemanticError as e:
                if show_stages:
                    print(f"语义错误: {e}")
                result["stages"]["semantic"] = {"status": "error", "error": e.to_dict()}
                result["error"] = e.to_dict()
                return result
            
            # 4. 执行计划生成
            if show_stages:
                print("\n=== 执行计划生成 ===")
            
            plans = self.planner.plan(ast_nodes)
            
            if show_stages:
                self._print_plans(plans)
            
            result["stages"]["plans"] = [plan.to_dict() for plan in plans]
            
            # 5. 执行
            if show_stages:
                print("\n=== 执行结果 ===")
            
            execution_result = self._execute_plans(plans)
            result["stages"]["execution"] = execution_result
            
            result["success"] = True
            
        except LexerError as e:
            result["error"] = e.to_dict()
            if show_stages:
                print(f"词法错误: {e}")
        except ParserError as e:
            result["error"] = e.to_dict()
            if show_stages:
                print(f"语法错误: {e}")
        except Exception as e:
            result["error"] = {"error_type": "EXECUTION_ERROR", "reason": str(e)}
            if show_stages:
                print(f"执行错误: {e}")
        
        self.results.append(result)
        return result
    
    def _print_tokens(self, tokens: List):
        """打印Token列表"""
        for i, token in enumerate(tokens):
            print(f"{i:2d}: {token}")
    
    def _print_ast(self, ast_nodes: List):
        """打印AST"""
        for i, node in enumerate(ast_nodes):
            print(f"Statement {i+1}:")
            print(node)
    
    def _print_plans(self, plans: List):
        """打印执行计划"""
        for i, plan in enumerate(plans):
            print(f"Plan {i+1}:")
            print(plan)
            print(f"JSON: {plan.to_json()}")
            print(f"S-expression: {plan.to_s_expression()}")
    
    def _ast_to_dict(self, ast_nodes: List) -> List[Dict]:
        """将AST转换为字典格式"""
        result = []
        for node in ast_nodes:
            result.append(self._node_to_dict(node))
        return result
    
    def _node_to_dict(self, node) -> Dict:
        """递归将AST节点转换为字典"""
        return {
            "node_type": node.node_type.value,
            "value": node.value,
            "children": [self._node_to_dict(child) for child in node.children]
        }
    
    def _execute_plans(self, plans: List) -> Dict[str, Any]:
        """执行计划"""
        execution_results = []
        
        for plan in plans:
            try:
                if plan.node_type.value == "CREATE_TABLE":
                    table_info = plan.properties.get("table_info")
                    result = self.executor.execute_create_table(table_info)
                    execution_results.append({
                        "operation": "CREATE_TABLE",
                        "success": result,
                        "message": "Table created successfully" if result else "Table already exists"
                    })
                elif plan.node_type.value == "INSERT":
                    table_name = plan.properties.get("table_name")
                    values = plan.properties.get("values", [])
                    result = self.executor.execute_insert(table_name, values)
                    execution_results.append({
                        "operation": "INSERT",
                        "success": result,
                        "message": "Record inserted successfully" if result else "Insert failed"
                    })
                elif plan.node_type.value in ("PROJECT", "SEQ_SCAN", "FILTER"):
                    # SELECT操作
                    table_name, columns, condition_func = self._extract_select_params(plan)
                    records = self.executor.execute_select(table_name, columns, condition_func)
                    execution_results.append({
                        "operation": "SELECT",
                        "success": True,
                        "records": records,
                        "count": len(records)
                    })
                elif plan.node_type.value == "DELETE":
                    table_name, _, condition_func = self._extract_select_params(plan.children[0] if plan.children else plan)
                    count = self.executor.execute_delete(table_name, condition_func)
                    execution_results.append({
                        "operation": "DELETE",
                        "success": True,
                        "deleted_count": count
                    })
                else:
                    execution_results.append({
                        "operation": plan.node_type.value,
                        "success": False,
                        "message": f"Unsupported operation: {plan.node_type.value}"
                    })
            except Exception as e:
                execution_results.append({
                    "operation": plan.node_type.value,
                    "success": False,
                    "error": str(e)
                })
        
        return {"results": execution_results}
    
    def _extract_select_params(self, plan):
        """从计划树中提取SELECT参数"""
        from sql_compiler.parser import ASTNodeType
        
        table_name = None
        columns = ["*"]
        condition_func = None
        
        stack = [plan]
        while stack:
            node = stack.pop()
            if node.node_type.value == "SEQ_SCAN":
                table_name = node.properties.get("table_name")
            elif node.node_type.value == "PROJECT":
                columns = node.properties.get("columns", ["*"])
            elif node.node_type.value == "FILTER":
                condition_ast = node.properties.get("condition_ast")
                if condition_ast is not None:
                    condition_func = self._build_condition_func(condition_ast)
            for child in node.children:
                stack.append(child)
        return table_name, columns, condition_func
    
    def _build_condition_func(self, expr):
        """构建条件函数"""
        from sql_compiler.parser import ASTNodeType
        
        def eval_expr(node, row):
            if node.node_type == ASTNodeType.COLUMN_REF:
                return row.get(node.value)
            if node.node_type == ASTNodeType.VALUE:
                return node.value
            if node.node_type == ASTNodeType.BINARY_OP:
                left = eval_expr(node.children[0], row)
                right = eval_expr(node.children[1], row)
                op = node.value
                symbol = getattr(op, 'value', str(op))
                if symbol == '=':
                    return left == right
                if symbol == '>':
                    return left > right
                if symbol == '<':
                    return left < right
                if symbol == '>=':
                    return left >= right
                if symbol == '<=':
                    return left <= right
                if symbol == '<>':
                    return left != right
                return False
            return False
        
        return lambda row: bool(eval_expr(expr, row))
    
    def run_from_file(self, file_path: str) -> List[Dict[str, Any]]:
        """从文件运行SQL语句"""
        with open(file_path, 'r', encoding='utf-8') as f:
            content = f.read()
        
        # 按分号分割语句
        statements = [stmt.strip() for stmt in content.split(';') if stmt.strip()]
        
        results = []
        for stmt in statements:
            result = self.run_sql(stmt, show_stages=False)
            results.append(result)
        
        return results
    
    def run_interactive(self):
        """交互式运行"""
        print("SQL Runner - 交互式模式")
        print("输入SQL语句，输入'exit'退出，输入'help'查看帮助")
        
        while True:
            try:
                sql = input("\nSQL> ").strip()
                
                if sql.lower() == 'exit':
                    break
                elif sql.lower() == 'help':
                    self._print_help()
                    continue
                elif not sql:
                    continue
                
                result = self.run_sql(sql)
                
                if self.output_format == "json":
                    print(json.dumps(result, indent=2, ensure_ascii=False))
                
            except KeyboardInterrupt:
                print("\n使用'exit'退出")
            except Exception as e:
                print(f"错误: {e}")
    
    def _print_help(self):
        """打印帮助信息"""
        print("""
支持的SQL语句：
- CREATE TABLE table_name (col1 TYPE, col2 TYPE, ...)
- INSERT INTO table_name VALUES (val1, val2, ...)
- SELECT * FROM table_name [WHERE condition]
- SELECT col1, col2 FROM table_name [WHERE condition]
- DELETE FROM table_name [WHERE condition]

示例：
- CREATE TABLE students (id INT, name VARCHAR(50), age INT)
- INSERT INTO students VALUES (1, 'Alice', 20)
- SELECT * FROM students WHERE age > 18
- DELETE FROM students WHERE id = 1

命令：
- exit: 退出程序
- help: 显示此帮助信息
        """)
    
    def get_results_summary(self) -> Dict[str, Any]:
        """获取结果摘要"""
        total = len(self.results)
        successful = sum(1 for r in self.results if r["success"])
        failed = total - successful
        
        return {
            "total_statements": total,
            "successful": successful,
            "failed": failed,
            "success_rate": successful / total if total > 0 else 0
        }

def main():
    """主函数"""
    import argparse
    
    parser = argparse.ArgumentParser(description="SQL Runner - 支持多语句输入和分阶段输出")
    parser.add_argument("--file", "-f", help="从文件读取SQL语句")
    parser.add_argument("--format", choices=["text", "json"], default="text", help="输出格式")
    parser.add_argument("--interactive", "-i", action="store_true", help="交互式模式")
    
    args = parser.parse_args()
    
    runner = SQLRunner(output_format=args.format)
    
    if args.file:
        # 从文件运行
        results = runner.run_from_file(args.file)
        if args.format == "json":
            print(json.dumps(results, indent=2, ensure_ascii=False))
        else:
            for result in results:
                print(f"SQL: {result['sql']}")
                print(f"结果: {'成功' if result['success'] else '失败'}")
                if result['error']:
                    print(f"错误: {result['error']}")
                print("-" * 50)
    elif args.interactive:
        # 交互式模式
        runner.run_interactive()
    else:
        # 从标准输入读取
        print("请输入SQL语句（输入'exit'退出）:")
        runner.run_interactive()
    
    # 显示摘要
    summary = runner.get_results_summary()
    print(f"\n执行摘要: {summary['successful']}/{summary['total_statements']} 成功")

if __name__ == "__main__":
    main()

